#include "MemPool.h"
#include <assert.h>
#include <algorithm>

using std::max;

MemPool::MemPool( size_t objectSize, size_t objectAlignment, size_t numObjects ) :
	m_chunks(),
	m_freelist( NULL ),
	m_object_size( objectSize ),
	m_object_alignment( objectAlignment ),  
	m_num_objects( numObjects ),
	m_num_allocated( 0 )
{
	m_chunks.reserve( 1 );
	Resize();
}

MemPool::~MemPool()
{
	for ( std::vector<void*>::iterator chunk = m_chunks.begin(); chunk != m_chunks.end(); ++chunk )
	{
		free( *chunk );        
	}
	m_chunks.clear();
}

void* MemPool::Allocate( size_t objectSize )
{
	assert( objectSize <= m_object_size );

	if ( !m_freelist )
	{
		Resize();
	}
    
	++m_num_allocated;

	assert( m_freelist );
	void* object = m_freelist;
	m_freelist = m_freelist->m_next;
	return object;
}

void MemPool::Deallocate( void* address )
{
	assert( address );
	--m_num_allocated;
	FreeList* freeList = (FreeList*) address;
	freeList->m_next = m_freelist;
	m_freelist = freeList;
}

size_t MemPool::Allocated() const
{
	return m_num_allocated;
}

void MemPool::Resize()
{
	//assert( m_chunks.size() < m_chunks.capacity() );
    
	// TODO : malloc with alignment
	//void* chunk = malloc( m_num_objects * m_object_size, m_object_alignment );
	void* chunk = malloc( m_num_objects * m_object_size );
	m_chunks.push_back( chunk );
    
	char* object = (char*) chunk;
	for ( size_t i = 0; i < m_num_objects; ++i )
	{
		FreeList* freeList = (FreeList*) object;
		freeList->m_next = m_freelist;
		m_freelist = freeList;
		object += m_object_size;
	}    
}
